package com.nova.bluetooth.xunFeiSDK.optionalFunction;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.iflytek.aiui.AIUIAgent;
import com.iflytek.aiui.AIUIConstant;
import com.iflytek.aiui.AIUIListener;
import com.iflytek.aiui.AIUIMessage;
import com.nova.bluetooth.R;
import com.nova.bluetooth.xunFeiSDK.engine.AiuiEngine;
import com.nova.bluetooth.xunFeiSDK.engine.EngineConstants;
import com.nova.bluetooth.xunFeiSDK.recorder.AudioRecorder;
import com.nova.bluetooth.xunFeiSDK.recorder.RecorderFactory;
import com.nova.bluetooth.xunFeiSDK.recorder.SystemRecorder;
import com.nova.bluetooth.xunFeiSDK.utils.CopyAssetsUtils;
import com.nova.bluetooth.xunFeiSDK.utils.ErrorCode;
import com.nova.bluetooth.xunFeiSDK.utils.senselessWordUtil;


import java.nio.charset.StandardCharsets;

/**
 * @author yanzhang59
 * Created on 2022/5/5 14:24
 * Email:yanzhang59@iflytek.com
 * Desc: 所见即可说demo
 * 注意事项：
 * 1.需要自定义技能，demo内使用的是自定义技能“动画”
 * 2.参考文档：https://www.yuque.com/iflyaiui/zzoolv/ckl01z
 */
public class SayWhenSeeingActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = DynamicEntityActivity.class.getSimpleName();
    Handler handler = new Handler();
    private TextView mResText;
    private ScrollView mScrollView;
    private Button sendDynamicText;
    private Button asrResult;
    private AIUIAgent mAIUIAgent = null;
    private AudioRecorder recorder;
    /**
     * 记录上传动态实体的id，方便查询是否创建成功
     */
    private String mSyncSid = "";

    /**
     * AIUI 回调信息处理
     */
    private AIUIListener mAIUIListener = event -> {
        switch (event.eventType) {
            case AIUIConstant.EVENT_CONNECTED_TO_SERVER:
                Log.i(TAG, "已连接服务器");
                break;

            case AIUIConstant.EVENT_CMD_RETURN: {
                if (AIUIConstant.CMD_SYNC == event.arg1) {    // 数据同步的返回
                    int dtype = event.data.getInt("sync_dtype", -1);
                    int retCode = event.arg2;

                    if (dtype == AIUIConstant.SYNC_DATA_SCHEMA) {
                        if (AIUIConstant.SUCCESS == retCode) {
                            // 上传成功，记录上传会话的sid，以用于查询数据状态
                            // 注：上传成功不等于数据生效，数据生效后才能正常使用
                            mSyncSid = event.data.getString("sid");

                            // 获取上传调用时设置的自定义tag
                            String tag = event.data.getString("tag");
                            setText("上传成功，sid=" + mSyncSid + "，tag=" + tag + "，你可以试着说“打电话给刘德华”");
                        } else {
                            mSyncSid = "";
                            setText("上传失败，错误码：" + retCode);
                        }
                    }
                } else if (AIUIConstant.CMD_QUERY_SYNC_STATUS == event.arg1) {    // 数据状态查询的返回
                    // 获取同步类型
                    int syncType = event.data.getInt("sync_dtype", -1);
                    if (AIUIConstant.SYNC_DATA_QUERY == syncType) {
                        // 若是同步数据查询，则获取查询结果，结果中error字段为0则表示上传数据打包成功，否则为错误码
                        String result = event.data.getString("result");
                        setText(result);
                    }
                }
            }
            break;
            case AIUIConstant.EVENT_RESULT:
                if (event.info.contains("\"sub\":\"nlp")) {
                    //收到语义结果，说明还在交互，重置交互时间
                    JSONObject cntJson = JSON.parseObject(new String(event.data.getByteArray("0"), StandardCharsets.UTF_8));
                    JSONObject nlpResult = cntJson.getJSONObject("intent");
                    //nlp无结果不处理
                    if (nlpResult.isEmpty()) {
                        return;
                    }
                    //如果只判断asr结果中的无意义词，若nlp先返回就可能被错误判断为无意义词
                    String asrResult = nlpResult.getString("text");
                    EngineConstants.meaningful = senselessWordUtil.isMeaningful_filter1word(asrResult);
                    //无意义词不处理
                    if (!EngineConstants.meaningful) {
                        return;
                    }
                    Log.i(TAG, "nlp result :" + nlpResult);
                    //在线语义结果,rc=0语义理解成功，rc≠0语义理解失败
                    setText(nlpResult.toString());
                }
                break;

            case AIUIConstant.EVENT_ERROR:
                setText("错误码: " + event.arg1);
                setText("错误信息:" + event.info);
                setText("解决方案:" + ErrorCode.getError(event.arg1) + "\n  错误解决详情参考：https://www.yuque.com/iflyaiui/zzoolv/igbuol");
                break;
            case AIUIConstant.EVENT_STATE:    // 状态事件
                EngineConstants.mAIUIState = event.arg1;
                break;
            default:
                break;
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_asr);
        initLayout();
        // 资源拷贝
        CopyAssetsUtils.portingFile(this);
    }

    @SuppressLint("SetTextI18n")
    private void initLayout() {
        findViewById(R.id.init_sdk).setOnClickListener(this);
        findViewById(R.id.btnStartRecord).setOnClickListener(this);
        findViewById(R.id.btnStopRecord).setOnClickListener(this);
        findViewById(R.id.btnSave).setOnClickListener(this);
        findViewById(R.id.writeTest).setOnClickListener(this);
        TextView titleTextView = findViewById(R.id.myTitle);
        titleTextView.setText("所见即可说demo");
        mScrollView = findViewById(R.id.scrollView);
        mResText = findViewById(R.id.res_text);
        Button btnStartRecord = findViewById(R.id.btnStartRecord);
        sendDynamicText = findViewById(R.id.btnStopRecord);
        sendDynamicText.setText("上传动画片名");
        asrResult = findViewById(R.id.writeTest);
        asrResult.setText("");
        asrResult.setVisibility(View.VISIBLE);
        mResText.append("默认oneshot模式 \n 点击上传动画片名，将上传以下内容：火影|火影忍者|海贼王|航海王|高达|敢达 \n 点击录音说我想看XX（XX为所上传的词条）即可体验 \n");
    }

    @Override
    public void onClick(View view) {
        int id = view.getId();
        if (id == R.id.init_sdk) {
            initSDK();
        } else if (id == R.id.btnStartRecord) {
            startRecord();
            //上传热词和语义内容
        } else if (id == R.id.btnStopRecord) {
            syncDataSpeakable();
        }
    }

    private void syncDataSpeakable() throws JSONException {
        JSONObject syncDataJson = new JSONObject();
        // 创建识别热词
        JSONObject iatDataJson = new JSONObject();
        iatDataJson.put("recHotWords", "火影|火影忍者|海贼王|航海王|高达|敢达");
        iatDataJson.put("sceneInfo", new JSONObject());
        syncDataJson.put("iat_user_data", iatDataJson);

        // 创建语义数据
        JSONObject nlpDataJson = new JSONObject();
        JSONArray res = new JSONArray();
        JSONObject resData = new JSONObject();

        //上传数据
        String cartoon =
                "{\"name\":\"火影\",\"alias\":\"火赢忍者\"}\n" +
                        "{\"name\":\"海贼王\",\"alias\":\"航海王\"}\n" +
                        "{\"name\":\"高达\",\"alias\":\"敢达\"}";
        resData.put("data", Base64.encodeToString(cartoon.getBytes(), Base64.DEFAULT | Base64.NO_WRAP));
        resData.put("res_name", "OS13466406899.CartoonName_name");
        res.add(0, resData);
        nlpDataJson.put("skill_name", "OS13466406899.cartoon");
        nlpDataJson.put("res", res);
        syncDataJson.put("nlp_user_data", nlpDataJson);

        byte[] syncData = syncDataJson.toString().getBytes(StandardCharsets.UTF_8);

        /**
         * 所见即可说使用用户级，需要设置uid，该设置值值为空，仅限该设备使用
         */
        String setParams = "{\"audioparams\":{\"pers_param\":{\"uid\":\"\"}}}";
        AIUIMessage syncAthenaMessage = new AIUIMessage(AIUIConstant.CMD_SYNC, AIUIConstant.SYNC_DATA_SPEAKABLE, 0, setParams, syncData);
        mAIUIAgent.sendMessage(syncAthenaMessage);
//        AiuiEngine.SayWhenSeeing(syncData);
    }


    private void initSDK() {
        //状态初始化
        EngineConstants.isRecording = false;
        //TODO 开发者需要实现生成sn的代码，参考：https://www.yuque.com/iflyaiui/zzoolv/tgftb5
        //注意事项1: sn每台设备需要唯一！！！！WakeupEngine的sn和AIUI的sn要一致
        //注意事项2: 获取的值要保持稳定，否则会重复授权，浪费授权量
        EngineConstants.serialNumber = "iflytek-test";
        Log.i(TAG, "sn : " + EngineConstants.serialNumber);
        // 初始化AIUI(识别+语义+合成）
        mAIUIAgent = AiuiEngine.getInstance(mAIUIListener, "cfg/aiui_sayWhenSeeing.cfg");
        if (mAIUIAgent != null) {
            setText("AIUI初始化成功");
        } else {
            setText("AIUI初始化失败");
        }

        recorder = RecorderFactory.getRecorder();
        //对音频的处理为识别模式
        SystemRecorder.AUDIO_TYPE_ASR = true;
        if (recorder != null) {
            setText("录音机初始化成功");
        } else {
            setText("录音机初始化失败");
        }
    }

    private void startRecord() {
        if (recorder != null) {
            int ret = recorder.startRecord();
            if (0 == ret) {
                setText("开启录音成功！");
            } else if (111111 == ret) {
                setText("异常,AlsaRecorder is null ...");
            } else {
                setText("开启录音失败，请查看/dev/snd/下的设备节点是否有777权限！\nAndroid 8.0 以上需要暂时使用setenforce 0 命令关闭Selinux权限！");
                destroyRecord();
            }
        }
    }

    private void stopRecord() {
        if (EngineConstants.isRecording && recorder != null) {
            recorder.stopRecord();
            EngineConstants.isRecording = false;
            setText("停止录音");
        }
    }

    private void syncQuery() {
        if (null == mAIUIAgent) {
            setText("AIUIAgent 为空，请先创建");
            return;
        }
        if (TextUtils.isEmpty(mSyncSid)) {
            setText("sid 为空");
            return;
        }
        try {
            // 构造查询json字符串，填入同步schema数据返回的sid
            JSONObject queryJson = new JSONObject();
            queryJson.put("sid", mSyncSid);

            // 发送同步数据状态查询消息，设置arg1为schema数据类型，params为查询字符串
            AIUIMessage syncQuery = new AIUIMessage(AIUIConstant.CMD_QUERY_SYNC_STATUS,
                    AIUIConstant.SYNC_DATA_SCHEMA, 0, queryJson.toString(), null);
            mAIUIAgent.sendMessage(syncQuery);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    private void destroyRecord() {
        if (null != recorder) {
            recorder.stopRecord();
        } else {
            Log.d(TAG, "destroy is Done!");
        }
    }


    /**
     * 根据scrollView 和子view去测量滑动的位置
     *
     * @param scrollView ScrollView
     * @param view       View
     */
    private void scrollToBottom(final ScrollView scrollView, final View view) {

        handler.post(() -> {
            if (scrollView == null || view == null) {
                return;
            }
            // offset偏移量。是指当textview中内容超出 scrollview的高度，那么超出部分就是偏移量
            int offset = view.getMeasuredHeight()
                    - scrollView.getMeasuredHeight();
            if (offset < 0) {
                offset = 0;
            }
            //scrollview开始滚动
            scrollView.scrollTo(0, offset);
        });
    }

    private void setText(final String str) {
        if (Looper.getMainLooper() == Looper.myLooper()) {
            mResText.append(str + " \n");
            scrollToBottom(mScrollView, mResText);
        } else {
            runOnUiThread(() -> {
                mResText.append(str + " \n");
                scrollToBottom(mScrollView, mResText);
            });
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (EngineConstants.isRecording) {
            stopRecord();
        }
        if (recorder != null) {
            recorder = null;
        }
        if (mAIUIListener != null) {
            mAIUIListener = null;
        }
        AiuiEngine.destroy();
    }
}
